package com.swagger.demo.config;

import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.jackson.annotation.JsonView;
import com.google.common.base.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.ModelReference;
import springfox.documentation.schema.TypeNameExtractor;
import springfox.documentation.schema.Types;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.contexts.ModelContext;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;

import static com.google.common.collect.Sets.newHashSet;
import static springfox.documentation.schema.ResolvedTypes.modelRefFactory;
import static springfox.documentation.spring.web.readers.operation.ResponseMessagesReader.httpStatusCode;
import static springfox.documentation.spring.web.readers.operation.ResponseMessagesReader.message;

/**
 * @author honeypie
 * 把解析后的response返回值类型填充到swagger文档中
 *
 * 参考代码：
 * <dependency>
 *     <groupId>com.github.xiaoymin</groupId>
 *     <artifactId>swagger-bootstrap-ui</artifactId>
 *     <version>1.9.6</version>
 * </dependency>
 * 此依赖中的DynamicResponseModelReader类
 *
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 1051)
public class JsonViewResponseModelReader implements OperationBuilderPlugin {

    private final TypeNameExtractor typeNameExtractor;

    @Autowired
    public JsonViewResponseModelReader(TypeNameExtractor typeNameExtractor) {
        this.typeNameExtractor = typeNameExtractor;
    }

    @Override
    public void apply(OperationContext context) {
        ResolvedType returnType = context.getReturnType();
        if (Types.isVoid(returnType)) return;

        Optional<JsonView> jsonViewOptional = context.findAnnotation(JsonView.class);
        if (jsonViewOptional.isPresent()) {
            Class<?>[] value = jsonViewOptional.get().value();
            if (value.length > 0) {

                String requestMappingPattern = context.requestMappingPattern();
                String method = "[" + context.httpMethod().name() + "]";
                // 拼接url和method得到缓存的key，比如：/addUser[POST]
                returnType = OperationJsonViewModelProvider.urlModelRefCache.get(requestMappingPattern + method);
                if (returnType == null) {
                    return;
                }

                int httpStatusCode = httpStatusCode(context);
                String message = message(context);

                ModelContext modelContext = ModelContext.returnValue(
                        context.getGroupName(),
                        returnType,
                        context.getDocumentationType(),
                        context.getAlternateTypeProvider(),
                        context.getGenericsNamingStrategy(),
                        context.getIgnorableParameterTypes());

                ModelReference modelRef = modelRefFactory(modelContext, typeNameExtractor).apply(returnType);

                ResponseMessage built = new ResponseMessageBuilder()
                        .code(httpStatusCode)
                        .message(message)
                        .responseModel(modelRef)
                        .build();

                context.operationBuilder().responseMessages(newHashSet(built));
            }
        }
    }

    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }
}
